package com.zhl.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/**
 * @author 凌晨
 * @Title: CustomGlobalFilter
 * @Description 校验全局过滤器
 * @date： 2020/10/16 22:15
 * @version： V1.0
 */
// 学习官方文档，发现对于过滤器有分为三类
// 1、默认过滤器 2、自定义过滤 3、全局过滤器
//    过滤器执行顺序结论
//  全局过滤器与其他2类过滤器相比，永远是最后执行的；它的优先级只对其他全局过滤器起作用
//  当默认过滤器与自定义过滤器的优先级一样时，优先出发默认过滤器，然后才是自定义过滤器；同类型的过滤器，出发顺序与他们在配置文件中声明的顺序一致
//  默认过滤器与自定义过滤器使用同样的order顺序空间，即他们会按照各自的顺序来进行排序
//    Spring Cloud Gateway 的 Filter 的生命周期有两个：“pre” 和 “post”。
//            “pre”：请求被执行前调用
//            “post”：被执行后调用
@Component
@Slf4j
public class CustomGlobalFilter implements GlobalFilter /**, Ordered*/ {
    private static final String AUTHORIZE_TOKEN = "token";
    private static final String AUTHORIZE_UID = "uid";

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("  pre 自定义过滤器工厂  " + this.getClass().getSimpleName());
        ServerHttpRequest request = exchange.getRequest();
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(AUTHORIZE_TOKEN);
        String uid = headers.getFirst(AUTHORIZE_UID);
        if (token == null) {
            token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
        }
        if (uid == null) {
            uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
        }

        ServerHttpResponse response = exchange.getResponse();
        if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", HttpStatus.UNAUTHORIZED.value());
            jsonObject.put("message", "请求非法，不允许直接访问");
            return generateJSON(exchange, jsonObject);
//            return response.setComplete();
        }
//        try {
//            String authToken = stringRedisTemplate.opsForValue().get(uid);
//            if (authToken == null || !authToken.equals(token)) {
//                //返回一个错误码 前端去做跳转淘宝授权登录页面 （前端处理）
////           exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
////           return exchange.getResponse().setComplete();
//                JSONObject jsonObject = new JSONObject();
//                jsonObject.put("code", HttpStatus.UNAUTHORIZED.value());
//                jsonObject.put("message", "认证失败");
//                return generateJSON(exchange, jsonObject);
//            }
//        }catch (Exception e){
//            log.error("AuthFilter.filter 错误信息{}", e.getMessage(), e);
//        }
//        return chain.filter(exchange);
        // 在then方法里的，相当于aop中的后置通知
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            System.out.println("  post 自定义过滤器工厂 " + this.getClass().getSimpleName());
        }));

    }

//    注意我们通过这种工厂创建出来的过滤器是没有指定order的，会被默认设置为是0，配置在yml文件中，则按照它书写的顺序来执行
//    如果想要在代码中设置好它的顺序，工厂的apply方法需要做一些修改
//    @Override
//    public int getOrder() {
//        return 0;
//    }

    private <T>Mono generateJSON(ServerWebExchange exchange, T t){
        ServerHttpResponse response = exchange.getResponse();
        byte[] bits = JSON.toJSONString(t).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        //指定编码，否则在浏览器中会中文乱码
        response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }
}
